/**
        Copyright (c) 2009 ATTi 
        All rights reserved.
*/

trigger caseRoundRobin on Case (after insert, after update) {
	class userInfoClass{
	   	List<Assignment_Groups__c> lag;
	   	Integer idx;
	}
	if(trigger.isAfter){  
    	Set<Id> sGroupIds = new Set<Id>();
	    Set<Id> queueIds = new Set<Id>();
	    Set<Id> caseIds = new Set<Id>();
	    
	    Map<ID, ID> mAGQIdbyQueueId = caseRoundRobinClass.getmAGQIdbyQueueId();
	    
    	for(Case c : trigger.new){
    		// If the owner changes
	    	if(trigger.isInsert || trigger.isUpdate && c.OwnerId != trigger.oldMap.get(c.Id).OwnerId){
	    		// See if the owner (i.e. queue) is linked to an assignment group
		    	if(mAGQIdbyQueueId.containsKey(c.OwnerId)){
		    		Id gId = mAGQIdbyQueueId.get(c.OwnerId);
		    		sGroupIds.add(gId);
		    		queueIds.add(c.OwnerId);
		    		caseIds.add(c.Id);
		    	}
	    	}
	    }
		    
	    if(!caseIds.isEmpty()){
	    	List<Case> lupdateCase = new List<Case>();
	    	Map<Id, userInfoClass> mGroupMember = new Map<Id, userInfoClass>();
	    	Map<Id, Assignment_Groups__c> mUpdateAG = new Map<Id, Assignment_Groups__c>();
	    		    	
	    	List<Case> lCase = new List<Case>([select Id, OwnerId, CaseNumber from Case where Id IN: caseIds]);
	    	List<Assignment_Groups__c> lAG = new List<Assignment_Groups__c>([select a.Id, a.Name, a.Group_Name__c, a.User__c from Assignment_Groups__c a
	    	                                                                 where  a.Active__c =: 'true' 
	    	                                                                 and a.User_Active__c =: 'true' 
	    	                                                                 and a.Group_Name__r.Type__c = 'Cases'
	    	                                                                 and a.Group_Name__c IN: sGroupIds
	    	                                                                 ORDER BY Last_Assignment__c, Millisecond__c] );
	    	for(Id gId : sGroupIds){
	    		List<Assignment_Groups__c> lagroup = new List<Assignment_Groups__c>();
	    		for(Assignment_Groups__c ag : lAG){
	    			if(ag.Group_Name__c == gId){
	    				lagroup.add(ag);
	    			}	
	    		}
	    		if(!lagroup.isEmpty()){
	    			userInfoClass u = new userInfoClass();
	    			u.lag = lagroup;
	    			u.idx = 0;
	    			for(ID qId : queueIds){
	    				if(mAGQIdbyQueueId.get(qId) == gId){
	    					mGroupMember.put(qId, u);
	    				}
	    			}
	    		}
	    	}
	    	
	    	for(Case c : lCase){
	    		if(mGroupMember.containsKey(c.OwnerId)){
	    			userInfoClass u_item = mGroupMember.get(c.OwnerId);
	    			Assignment_Groups__c ag_item = u_item.lag[u_item.idx];
	    			System.debug('Test CaseNumber = ' + c.CaseNumber + ' Ownere change from ' + c.OwnerId + ' to ' + ag_item.User__c);
	    			c.OwnerId = ag_item.User__c;
	    			lupdateCase.add(c); // add into case update list
	    			if(!mUpdateAG.containsKey(ag_item.Id)){
	    				datetime now = datetime.now();
	    				ag_item.Last_Assignment__c = now;
	    				ag_item.Millisecond__c = now.millisecondGMT();
	    				mUpdateAG.put(ag_item.Id, ag_item);
	    			}
	    			
                    u_item.idx++;
	    			u_item.idx = math.mod(u_item.idx, u_item.lag.size());
	    		}
	    	}
	    		    	
	    	try {
	    		update lupdateCase; // OwnerId must be updated again after insert/update
	    		update mUpdateAG.values(); // update Assignment Time for Assignment Group Member
	    	}catch (Exception ex){
	    		System.debug('Exception in update the Case and Assignment Group Member: ' + ex);
	    	}
	    }
	}
}